﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using InvariantWM;
using System.IO;
using AForge.Imaging;
using System.Drawing.Imaging;

namespace WindowsFormsApplication
{
    public partial class Main : Form
    {
        int moreCount;
        int diameter = InvariantWM.Properties.Settings.Default.diameter;
        Bitmap originalBitmap, currentBitmap, b1, b2, b3a, b3b, b4b, b5b, b6, b6a, b7;
        int currentStep, auxStep;
        Normalizer normalizer;
        List<Bitmap> esquinasBitmap = new List<Bitmap>();
        List<Bitmap> esquinasBitmap2 = new List<Bitmap>();
        List<Bitmap> esquinasBitmap3 = new List<Bitmap>();
        List<Bitmap> esquinasBitmap4 = new List<Bitmap>();
        List<Normalizer> esquinasNormalizer = new List<Normalizer>();
        Point[] corners;
        double lado;
        double NC;

        public Main()
        {
            InitializeComponent();
            lado = Convert.ToDouble(diameter) / Math.Sqrt(2.0F);
        }

        private void stepByStep(int step)
        {
            Cursor.Current = Cursors.WaitCursor;
            if (step == 1)
            {
                esquinasBitmap.Clear();
                esquinasBitmap2.Clear();
                esquinasBitmap3.Clear();
                esquinasBitmap4.Clear();
                esquinasNormalizer.Clear();
                guardarComoToolStripMenuItem.Enabled = true;

                b1 = (Bitmap)originalBitmap.Clone();

                normalizer = new Normalizer(b1);
                b1 = normalizer.scaleNormalize(originalBitmap.Width * originalBitmap.Height);

                currentBitmap = b1;
                imagePictureBox.Image = currentBitmap;
                currentStepTextBox.Text = "Normalizar en escala una imagen consiste en conseguir una imagen escalada a partir de esta, cuadrada, con un cierto area. De esta forma, si tenemos dos imagenes escaladas en x e y en distintas proporciones, y las normalizamos, para que tengan una cierta area a, debemos obtener la misma imagen, o una casi coincidente. Y decimos casi coincidentes porque puede que en el primer escalado sufrido por la imagen, o bien en el realizado para normalizarla, se haya perdido algo de información. Es normal ésta perdida al escalar cualquier imagen en una proporción arbitraria, y no es posible evitarla excepto en casos concretos.";
                logNewLine("Normalización en escala realizada satisfactoriamente.");
                currentStep++;
            }
            else if (step == 2)
            {
                b2 = (Bitmap)b1.Clone();
                System.Drawing.Graphics gr = Graphics.FromImage(b2);
                gr.DrawImage(b2, new Rectangle(0, 0, b2.Width, b2.Height));
                CornerDetector scd = new CornerDetector();
                corners = scd.ProcessImage(b2);

                foreach (Point corner in corners)
                {
                    gr.DrawEllipse(new Pen(Brushes.Red), corner.X - diameter / 2, corner.Y - diameter / 2, diameter, diameter);
                    b2.SetPixel(corner.X, corner.Y, Color.Red);

                    Bitmap tempb = new Bitmap(diameter, diameter);
                    Graphics tempGr = Graphics.FromImage(tempb);
                    Point upperleft = new Point(-corner.X + diameter / 2, -corner.Y + diameter / 2);
                    tempGr.DrawImage(b1, upperleft);
                    esquinasBitmap.Add(tempb);
                }

                currentBitmap = b2;
                //currentBitmap = esquinasBitmap[0];
                imagePictureBox.Image = currentBitmap;
                currentStepTextBox.Text = "Usamos el detector de esquinas para aislar una serie de puntos singulares entorno a los cuales incrustar la marca de agua.";
                logNewLine("Esquinas detectadas satisfactoriamente.");
                currentStep++;
            }
            else if (step == 3)
            {
                auxStep = 3;
                int i = 0;
                while (i < esquinasBitmap.Count)
                {
                    Bitmap b3 = esquinasBitmap[i];
                    Normalizer tempNormalizer = new Normalizer(b3);
                    esquinasNormalizer.Add(tempNormalizer);
                    esquinasBitmap[i] = tempNormalizer.rotationNormalize();
                    i++;
                }

                //b3a = (Bitmap)esquinasBitmap[0].Clone();
                //Graphics tempGr = Graphics.FromImage(b3a);
                //tempGr.DrawRectangle(new Pen(Brushes.Red), (float)((diameter - lado) / 2), (float)((diameter - lado) / 2), (float)lado, (float)lado);

                //currentBitmap = b3a;
                //imagePictureBox.Image = currentBitmap;
                if (esquinasBitmap.Count > 1)
                    moreButton.Visible = true;
                moreButton_Click(this, new EventArgs());
                currentStepTextBox.Text = "Normalizar en rotación una imagen consiste en hayar su centroide, y a partir de ciertos calculos estadísticos realizados usando los momentos momentos de ésta, obtener un angulo y rotar la imagen según dicho ángulo. Tal angulo, tiene la propiedad de que, obtenido de distintas versiones de una misma imagen, rotadas con distintas orientaciones, y aplicado a estas, consigue hacerlas coincidir a todas, es decir, las pone a todas del derecho, convirtiendolas a todas en la misma, analogamente a lo que pasaba con la normalización en escala.";
                logNewLine("Normalización en rotación realizada satisfactoriamente.");
                currentStep++;
            }
            else if (step == 4)
            {
                auxStep = 4;
                int i = 0;
                foreach (Point corner in corners)
                {
                    Bitmap tempb = new Bitmap((int)lado, (int)lado);
                    Graphics tempGr = Graphics.FromImage(tempb);
                    Point upperleft = new Point((int)((lado - diameter) / 2), (int)((lado - diameter) / 2));
                    tempGr.DrawImage(esquinasBitmap[i], upperleft);
                    esquinasBitmap2.Add(tempb);
                    i++;
                }

                moreCount = 0;
                if (esquinasBitmap2.Count > 1)
                    moreButton.Visible = true;
                moreButton_Click(this, new EventArgs());
                //currentBitmap = esquinasBitmap2[0];
                //imagePictureBox.Image = currentBitmap;
                currentStepTextBox.Text = "Recortamos el parche donde se incrustará la marca de agua.";
                logNewLine("Recorte realizado satisfactoriamente.");
                currentStep++;
            }
            else if (step == 5)
            {
                auxStep = 5;
                if (watermarkTextBox.Text != "")
                {
                    NC = 0;
                    foreach (Bitmap b5 in esquinasBitmap2)
                    {
                        /* Bitmap aux = WatermarkProcessor.insertWatermark(b5, watermarkTextBox.Text);
                         esquinasBitmap3.Add(aux);*/
                        double tmp = WatermarkProcessor.testWatermark(b5, watermarkTextBox.Text);
                        //logNewLine("El valor NC es" + NC);
                        if (tmp > NC)
                            NC = tmp;
                    }

                    moreCount = 0;
                    if (esquinasBitmap3.Count > 1)
                        moreButton.Visible = true;
                    moreButton_Click(this, new EventArgs());
                    //currentBitmap = esquinasBitmap3[0];
                    //imagePictureBox.Image = currentBitmap;
                    NC = Math.Max(NC, WatermarkProcessor.extracterAUX(originalBitmap, watermarkTextBox.Text));
                    currentStepTextBox.Text = "Extraemos una marca de agua a cada uno de los parches previamente extraidos.";
                    logNewLine("Marca de agua extraida satisfactoriamente. El valor de correlación es: " + NC);
                    currentStep++;
                }
                else
                {
                    MessageBox.Show("Debe insertar una clave para incrustar la marca de agua en el campo Watermark.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    logNewLine("Error: Debe insertar una clave para incrustar la marca de agua en el campo Watermark.");
                }
            }/*
            else if (step == 6)
            {
                moreButton.Visible = false;
                previousButton.Visible = false;
                int j = 0;
                foreach (Bitmap esquina in esquinasBitmap3)
                {
                    esquinasBitmap4.Add(esquinasNormalizer[j].inverseRotationNormalize(esquina));

                    j++;
                }

                b6 = new Bitmap(b1);
                b6a = new Bitmap(b1);
                Graphics gr = Graphics.FromImage(b6);
                Graphics gra = Graphics.FromImage(b6a);
                int i = 0;
                foreach (Point corner in corners)
                {
                    b6a.SetPixel(corner.X, corner.Y, Color.Red);
                    gra.DrawRectangle(new Pen(Brushes.Red), (float)(corner.X - lado / 2), (float)(corner.Y - lado / 2), (float)lado, (float)lado);

                    gr.DrawImage(esquinasBitmap4[i], new Point((int)(corner.X - lado/2), (int)(corner.Y - lado/2)));
                    i++;
                }

                currentBitmap = b6a;
                imagePictureBox.Image = currentBitmap;
                currentStepTextBox.Text = "Hacemos la inversa de la normalización en rotación y reinsertamos los parches con la marca de agua en la imagen original.";
                logNewLine("Inversa de la normalización en rotación y parches reinsertados satisfactoriamente.");
                currentStep++;
            }*/
            else if (step == 6)
            {/*
                b7 = (Bitmap)b6.Clone();
                b7 = normalizer.inverseScaleNormalize(b7);

                currentBitmap = b7;
                imagePictureBox.Image = currentBitmap;
                currentStepTextBox.Text = "Hacemos la inversa de la normalización en escala y mostramos la imagen final con la marca de agua insertada.";
                logNewLine("Inversa de la normalización en escala realizada satisfactoriamente.");
                logNewLine("Proceso completado satisfactoriamente.");
              * */
                nextButton.Enabled = false;
                completeButton.Enabled = false;
                currentStep++;
                resumeButton.Enabled = true;
                diffButton.Enabled = true;
               // guardarComoToolStripMenuItem_Click(this, new EventArgs());

                //imagePictureBox.Image = Differ.getDiff(originalBitmap, b7);
            }

            groupBox1.Text = "Paso " + currentStep;
            Cursor.Current = Cursors.Default;
        }

        private void logNewLine(string newLine)
        {
            logTextBox.Text += "[" + Convert.ToString(DateTime.Now.TimeOfDay).Substring(0, 8) + "] " + newLine + "\r\n";
            logTextBox.SelectionStart = logTextBox.Text.Length;
            logTextBox.ScrollToCaret();
        }

        private void salirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void abrirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            //ofd.InitialDirectory = "C:\\";
            ofd.Filter = "BMP (*.bmp;)|*.bmp";
            ofd.FilterIndex = 2;
            ofd.RestoreDirectory = true;

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    groupBox1.Text = "Paso 0";
                    diffButton.Enabled = false;
                    resumeButton.Enabled = false;
                    moreButton.Visible = false;
                    previousButton.Visible = false;
                    moreCount = 0;
                    currentStep = 0;
                    originalBitmap = new Bitmap(ofd.OpenFile());
                    imagePictureBox.Image = originalBitmap;
                    nextButton.Enabled = true;
                    completeButton.Enabled = true;
                    currentStepTextBox.Text = "Pulse 'Siguiente' para ejecutar el proceso paso a paso o 'Terminar' para obtener la imagen final.";
                    logNewLine("Se ha cargado la imagen " + ofd.FileName + " satisfactoriamente.");
                }
                catch (Exception)
                {
                    nextButton.Enabled = false;
                    completeButton.Enabled = false;
                    logNewLine("Se ha producido un error al cargar la imagen " + ofd.FileName + ".");
                }
            }
        }

        private void nextButton_Click(object sender, EventArgs e)
        {
            stepByStep(currentStep + 1);
        }

        private void completeButton_Click(object sender, EventArgs e)
        {
            for (int i = currentStep; i <= 7; i++)
            {
                stepByStep(i);
            }
        }

        public void guardarComoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.DefaultExt = "bmp";
            sfd.Filter = "BMP (*.bmp)|*.bmp";
            sfd.AddExtension = true;
            sfd.RestoreDirectory = true;
            sfd.InitialDirectory = "C:/";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                currentBitmap.Save(sfd.FileName);
                logNewLine("Se ha guardado la imagen satisfactoriamente en " + sfd.FileName);
            }

            sfd.Dispose();
            sfd = null;
        }

        private void acercaDeInvariantWatermarkingToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm aboutForm = new AboutForm();
            aboutForm.ShowDialog();
        }

        private void resumeButton_Click(object sender, EventArgs e)
        {
            ResumeForm resumeForm = new ResumeForm(originalBitmap, b1, b2, b3b, b4b, b5b, b6a, b7);
            resumeForm.Show();
        }

        private void moreButton_Click(object sender, EventArgs e)
        {
            if (auxStep == 3)
            {
                try
                {
                    moreCount++;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    b3a = (Bitmap)esquinasBitmap[moreCount - 1].Clone();
                    Graphics tempGr = Graphics.FromImage(b3a);
                    tempGr.DrawRectangle(new Pen(Brushes.Red), (float)((diameter - lado) / 2), (float)((diameter - lado) / 2), (float)lado, (float)lado);
                    currentBitmap = b3a;
                    imagePictureBox.Image = currentBitmap;

                    if (moreCount == 1)
                        b3b = (Bitmap)currentBitmap.Clone();
                }
                catch (Exception)
                {
                }
            }
            else if (auxStep == 4)
            {
                try
                {
                    moreCount++;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap2.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    currentBitmap = esquinasBitmap2[moreCount - 1];
                    imagePictureBox.Image = currentBitmap;

                    if (moreCount == 1)
                        b4b = (Bitmap)currentBitmap.Clone();
                }
                catch (Exception)
                {
                }
            }
            else if (auxStep == 5)
            {
                try
                {
                    moreCount++;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap3.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    currentBitmap = esquinasBitmap3[moreCount - 1];
                    imagePictureBox.Image = currentBitmap;

                    if (moreCount == 1)
                        b5b = (Bitmap)currentBitmap.Clone();
                }
                catch (Exception)
                {
                }
            }
        }

        private void previousButton_Click(object sender, EventArgs e)
        {
            if (auxStep == 3)
            {
                try
                {
                    moreCount--;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    b3a = (Bitmap)esquinasBitmap[moreCount - 1].Clone();
                    Graphics tempGr = Graphics.FromImage(b3a);
                    tempGr.DrawRectangle(new Pen(Brushes.Red), (float)((diameter - lado) / 2), (float)((diameter - lado) / 2), (float)lado, (float)lado);
                    currentBitmap = b3a;
                    imagePictureBox.Image = currentBitmap;
                }
                catch (Exception)
                {
                }
            }
            else if (auxStep == 4)
            {
                try
                {
                    moreCount--;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap2.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    currentBitmap = esquinasBitmap2[moreCount - 1];
                    imagePictureBox.Image = currentBitmap;
                }
                catch (Exception)
                {
                }
            }
            else if (auxStep == 5)
            {
                try
                {
                    moreCount--;

                    if (moreCount > 1)
                        previousButton.Visible = true;
                    else
                        previousButton.Visible = false;

                    if (moreCount > esquinasBitmap3.Count - 1)
                        moreButton.Visible = false;
                    else
                        moreButton.Visible = true;

                    currentBitmap = esquinasBitmap3[moreCount - 1];
                    imagePictureBox.Image = currentBitmap;
                }
                catch (Exception)
                {
                }
            }
        }

        private void ayudaToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            //HelpForm helpForm = new HelpForm();
            //helpForm.ShowDialog();
        }

        private void diffButton_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            DiffForm diffForm = new DiffForm(originalBitmap, b7, Differ.getDiff(originalBitmap, b7));
            diffForm.ShowDialog();
            Cursor.Current = Cursors.Default;
        }

        private void borrarRegistroToolStripMenuItem_Click(object sender, EventArgs e)
        {
            logTextBox.Text = "";
        }

        private void Main_Load(object sender, EventArgs e)
        {

        }

    }
}
